#ifndef CAP_RLIMIT_H
#define CAP_RLIMIT_H

#include <cap/cnode.h>
#include <cap/cap.h>

typedef struct cap_rlimit {
    cap_t cap;
    unsigned long limit_used;
    struct caprlimit *crlim;
} cap_rlimit_t;

extern const struct cap_ops rlimit_cap_ops;
extern cap_rlimit_t root_cap_rlimit;

cap_rlimit_t *rlimit_get(void);
static inline void rlimit_put(cap_rlimit_t *cap_rlimit)
{
    capput(&cap_rlimit->cap);
}

static inline void cap_set_rlimit(cap_t *cap, cap_rlimit_t *cap_rlimit)
{
    cap->cap_rlimit = cap_rlimit;
}

static inline cap_rlimit_t *rlimit_cap(cap_t *cap)
{
    return cap->cap_rlimit;
}

static inline bool rlimit_overflow(unsigned long limit, struct caprlimit *crlimit)
{
    return (limit + crlimit->rlim_cur >= crlimit->rlim_max);
}

static inline void rlimit_up(cap_t *cap, unsigned long limit)
{
    rlimit_cap(cap)->crlim[cap_get_cap_type(cap)].rlim_cur += limit;
}

static inline void rlimit_down(cap_t *cap)
{
    unsigned long limit = cap_rlimit_down(cap);
    rlimit_cap(cap)->crlim[cap_get_cap_type(cap)].rlim_cur -= limit;
}

#define INIT_ROOT_RLIMIT                \
{                                      \
    [cap_null_cap]         = { CAP_RLIMIT_INFINITY, CAP_RLIMIT_INFINITY },  \
    [cap_rlimit_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_cnode_cap]        = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_thread_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_devctl_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_device_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_devirq_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_deadline_cap]     = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_vspace_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_endpoint_cap]     = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_sigctl_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_sysctl_cap]       = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_frame_cap]        = {                   0, CAP_RLIMIT_INFINITY },  \
    [cap_page_cap]         = {                   0, CAP_RLIMIT_INFINITY },  \
}

cap_t *create_rlimit_obj(cap_rlimit_t *cap_rlimit, seminix_object_t *obj, int rights);

#endif /* !CAP_RLIMIT_H */
